
import os
import subprocess
import select
import asyncio
import time
import termios
import fcntl
import struct


# 空绑定
async def empty(*args):
    pass

# 读取输出


async def read_output(p, callback, bash_id):
    obuffer = b''
    exitflag = 0
    scan_tty_mode = 0
    scan_tty_buff = b""
    while True:
        # ts = time.time()

        def loadsout():
            nonlocal exitflag, obuffer
            # 读取stdout
            while True:
                # 判断是否可读
                ready, _, _ = select.select([p.stdout], [], [], 0.01)
                if ready:
                    data = p.stdout.read(1)  # 读取
                    if not data:
                        exitflag = 1
                        break
                    obuffer += data
                else:
                    break
            if (exitflag):
                return
            # 读取stderr
            while True:
                ready, _, _ = select.select([p.stderr], [], [], 0.01)
                if ready:
                    data = p.stderr.read(1)
                    if not data:
                        exitflag = 1
                        break
                    obuffer += data
                else:
                    break
            if (exitflag):
                return

        # 异步等待读取
        await asyncio.to_thread(loadsout)
        if (exitflag):
            break

        if (bash_id not in bash_lst):  # 断连检测
            break

        if (b"\x04" in obuffer):  # 检测终端输出的tty编号
            # 裁剪结果
            if (scan_tty_mode == 0):
                scan_tty_buff += obuffer.split(b"\x04")[1]
                scan_tty_mode = 1
                if (len(obuffer.split(b"\x04")) == 3):
                    scan_tty_mode = 2
                    bash_tty_lst[bash_id] = os.open(
                        scan_tty_buff.decode("utf-8"), os.O_RDWR)
            elif (scan_tty_mode == 1):
                scan_tty_buff += obuffer.split(b"\x04")[0]
                scan_tty_mode = 2
                bash_tty_lst[bash_id] = os.open(
                    scan_tty_buff.decode("utf-8"), os.O_RDWR)

        if (obuffer):
            await callback(obuffer)
            obuffer = b''

    # 进程退出
    await callback(("\n\n\033[0m\033[47;30m * \033[30;48;5;208m 进程已退出，退出代码 \033[42m "+str(p.poll())+" \033[0m").encode("utf-8"))
    await close_bash(bash_id)


def init():
    # 初始化
    global conn_cmd, bash_id, bash_lst, bash_tty_lst, termcallbacks, termoutput
    conn_cmd = os.path.dirname(
        __file__)+os.sep+'connect.sh'

    # 配置ssh
    if (not os.path.exists("~/.ssh/neutron-panel")):
        os.system("bash "+os.path.dirname(__file__)+os.sep+'init.sh')

    bash_lst = {}
    bash_tty_lst = {}
    bash_id = 0
    termcallbacks = {}
    termoutput = {}


async def run_bash(callback, termid: int = 0):
    # 运行bash
    global bash_id, bash_lst, bash_tty_lst
    p = subprocess.Popen([conn_cmd], stdin=subprocess.PIPE,
                         stdout=subprocess.PIPE, stderr=subprocess.PIPE,  bufsize=0, pipesize=0, universal_newlines=False)

    # 消除ide提示
    if (p.stdout is None):
        return None
    if (p.stdin is None):
        return None
    if (p.stderr is None):
        return None

    bash_lst[termid] = p
    bash_tty_lst[termid] = -1

    asyncio.create_task(read_output(p, callback, termid))
    return termid


async def close_bash(bash_id):
    # 关闭会话
    global bash_lst, bash_tty_lst
    if (bash_id not in bash_lst):
        return
    bash_lst[bash_id].kill()
    del bash_lst[bash_id]
    del bash_tty_lst[bash_id]
    del termcallbacks[bash_id]
    del termoutput[bash_id]


async def write_bash(bash_id, data):
    # 写入会话
    global bash_lst
    if (bash_id not in bash_lst):
        return
    bash_lst[bash_id].stdin.write(data)
    bash_lst[bash_id].stdin.flush()


async def set_term_size(termid, rows=10, cols=10):
    # 设置tty的缩放
    if (termid in bash_tty_lst and bash_tty_lst[termid] != -1):
        fcntl.ioctl(bash_tty_lst[termid], termios.TIOCSWINSZ,
                    struct.pack('HH', rows, cols))
